﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DiscreteMath
{
    /// <summary>
    /// Empty, immutable set. The point in using this class instead of private field is that this throws exception whenever an attempt to add something is made
    /// so this is error-proof.
    /// </summary>
    /// <typeparam name="T"></typeparam>
	class EmptySet<T> : IReadOnlyCollection<T>, ISet<T>
	{
		private static ISet<T> set = new HashSet<T>();

		private EmptySet()
		{ }

        public static ISet<T> Empty
        {
            get
            {
                return set;
            }
        }

		public int Count
		{
			get { return set.Count; }
		}

        public bool IsReadOnly
        {
            get { return true; }
        }

		public IEnumerator<T> GetEnumerator()
		{
			return set.GetEnumerator();
		}

		System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
		{
			return set.GetEnumerator();
		}

		public bool Add(T item)
		{
			throw new InvalidOperationException("This set is immutable and items may not be added!");
		}

		public void ExceptWith(IEnumerable<T> other)
		{
			// An empty set needs no removal of any items
		}

		public void IntersectWith(IEnumerable<T> other)
		{
			// An empty set has empty intersection
		}

		public bool IsProperSubsetOf(IEnumerable<T> other)
		{
			return other.Count() != 0;
		}

		public bool IsProperSupersetOf(IEnumerable<T> other)
		{
			return false;
		}

		public bool IsSubsetOf(IEnumerable<T> other)
		{
			return true;
		}

		public bool IsSupersetOf(IEnumerable<T> other)
		{
			return true;
		}

		public bool Overlaps(IEnumerable<T> other)
		{
			return false;
		}

		public bool SetEquals(IEnumerable<T> other)
		{
			return other.Count() == 0;
		}

		public void SymmetricExceptWith(IEnumerable<T> other)
		{
			// Nothing to do here
		}

		public void UnionWith(IEnumerable<T> other)
		{
			throw new InvalidOperationException("I IZ IMMUTABLE!");
		}

		void ICollection<T>.Add(T item)
		{
			this.Add(item);
		}

		public void Clear()
		{
			// Nothing to do here
		}

		public bool Contains(T item)
		{
			return false;
		}

		public void CopyTo(T[] array, int arrayIndex)
		{
			// Nothing to do here
		}

		public bool Remove(T item)
		{
			return false;
		}
	}
}
